﻿
// TODO: refator to use promises
var PERISCOPE = (function (targetElement) {
    var periscope = {
        includes: {},
        panelIdentity: null,
        debug: false,
        addWidgetCallback: null,
        start: function (panelName, debug, addWidgetCallback) {
            periscope.debug = debug;
            periscope.addWidgetCallback = addWidgetCallback;

            startSignalR(loadPanelContinuation(panelName));
        }
    };

    function buildUrl(path) {
        var url = window.location.protocol + '//' + location.host + '/dashboard';

        if (path) {
            return url + path;
        }
        return url;
    }

    function buildPanelUrl() {
        return buildUrl('/' + periscope.panelIdentity.panelName);
    }

    function log(message) {
        if (!periscope.debug)
            return;
        console.log(message);
    }

    function startSignalR(connectedCallback) {
        // Proxy created on the fly 'http://localhost:805/signalr/';
        var url = location.protocol + '//' + location.hostname + ':805/signalr/';
            
        $.connection.hub.url = url;
        $.connection.hub.stateChanged(function(state) {
            log("SignalR Connection State changed!...");
            log(state);

            var stateLookup = {
                0: 'connecting',
                1: 'connected',
                2: 'reconnecting',
                4: 'disconnected'
            };

            log('SignalR state: ' + stateLookup[state.oldState] + '->' + stateLookup[state.newState]);

            // TODO: fix this hardcoded ctrl ids
            // parameterise as callback fn's or raise events
            if (state.newState == 1) {
                $('#stateConnectedTellTale').show();
                $('#stateDisconnectedTellTale').hide();
                connectedCallback();
            } else {
                $('#stateConnectedTellTale').hide();
                $('#stateDisconnectedTellTale').show();
            }
        });

        var dashboard = $.connection.dashboard;


        // ==============================================================
        // client methods callable from the SignalR mothership
        // ==============================================================
        dashboard.client.panelRotateCommand = function (command) {
            log('panelRotateCommand received!');
            log(command);
        };

        dashboard.client.panelConfigChangedCommand = function (command) {
            log('panelConfigChangedCommand received!');
            log(command);

            if (command.PanelInstanceId) {
                if (command.PanelInstanceId == periscope.panelIdentity.panelInstanceId) {
                    log('ignoring update request as it was originated by this exact panel!');
                    return;
                }
            }

            if (command.PanelId == periscope.panelIdentity.panelId) {
                log('reloading panel due to remote config update...');
                window.location = buildPanelUrl();
            }
        };

        dashboard.client.widgetResizedCommand = function (command) {
            log('widgetResizedCommand received!');
            log(command);

            if (command.PanelId == periscope.panelIdentity.panelId) {
                log('reloading panel...');
                window.location = buildPanelUrl();
            }
        };

        dashboard.client.widgetAddedCommand = function (command) {
            log('widgetAddedCommand received!');
            log(command);

            if (command.PanelId == periscope.panelIdentity.panelId) {
                log('reloading panel...');
                window.location = buildPanelUrl();
            }
        };
        
        dashboard.client.widgetUpdateCommand = function (update) {
            log('widgetUpdateCommand received!');
                
            if (update.TargetPanelInstanceId) {
                if (update.TargetPanelInstanceId != periscope.panelIdentity.panelInstanceId) {
                    log('ignoring widget update, not for this panel instance!');
                    return;
                }
            }

            var payload = update.Payload.replace(/'/g, "\\'").replace(/(\r\n|\n|\r)/gm, "");
            var widgetScript = "if (window._" + update.TargetWidgetId + " && window._" + update.TargetWidgetId + ".update) { " +
                "log('widget updated!');" +
                "_" + update.TargetWidgetId + ".update('" + payload + "'); }";
            log(widgetScript);

            try {
                eval(widgetScript);
            } catch (error) {
                // TODO: fix this hardcoded ctrl id
                // parameterise as callback fn's or raise events
                log('error updating widget \'' + update.TargetWidgetId + '\': ' + error);
                // TODO: make this a dictionary and only show if any entries. remove entry if get successful subsequent update
                $('#updateIssuesTellTale').show();
            }
        };

        // Start the connection
        $.connection.hub.start();
    }

    function loadPanelContinuation(panelName) {
        return function() {
            loadPanel(panelName);
        }
    }

    function loadPanel(panelName) {
        var url = '/dashboard/panel/';

        if (panelName)
            url += panelName;

        $.ajax({
            type: 'GET',
            url: url,
            contentType: 'application/json; charset=utf-8',
            dataType: 'json'
        }).done(function (data, status, jqXhr) {
            log('got panel data...');
            log(data);

            loadStyleSheets(data, new loadMarkupContinuation(data));

        }).fail(function (jqXhr, status, err) {
            log('failed to get panel data');
            log(err);
        });
    }

    function loadMarkupContinuation(data) {
        return function() {
            loadGridsterMarkup(data, new loadScriptsContinuation(data));
        }
    }

    function loadScriptsContinuation(data) {
        return function() {
            loadScripts(data, new completeLoadingContinuation(data));
        }
    }

    function completeLoadingContinuation(data) {
        return function() {
            completeLoadingPanel(data);
        }
    }

    function loadStyleSheets(data, continueWith) {
        var stylesheets = [];

        if (data.styleSheets.length == 0) {
            continueWith();
            return;
        }

        $.each(data.styleSheets, function (index, css) {
            if (css.name in periscope.includes) {
                log(css.name + ' already loaded!');
            } else {
                periscope.includes[css.name] = css.value;
                stylesheets.push(css.value);
            }
        });

        if (stylesheets.length == 0) {
            continueWith();
            return;
        }

        log("loading stylesheets...");
        log(stylesheets);

        LazyLoad.css(stylesheets, function () {
            log("...done, running continueWith()...");
            continueWith();
        });
    }

    function loadGridsterMarkup(data, continueWith) {
        $.each(data.widgets, function (index, widget) {
            log("Creating widget: " + widget.id);
            periscope.addWidgetCallback(widget);
        });

        continueWith();
    }

    function loadScripts(data, continueWith) {
        var scripts = [];

        if (data.scripts.length == 0) {
            continueWith();
            return;
        }

        $.each(data.scripts, function (index, script) {
            if (script.name in periscope.includes) {
                log(script.name + ' already loaded!');
            } else {
                periscope.includes[script.name] = script.value;
                scripts.push(script.value);
            }
        });

        if (scripts.length == 0) {
            continueWith();
            return;
        }

        log("loading scripts...");
        log(scripts);

        LazyLoad.js(scripts, function () {
            log("...done, running continueWith()...");
            continueWith();
        });
    }

    function completeLoadingPanel(data) {
        // set identity
        periscope.panelIdentity = {
            panelId: data.id.toString(),
            panelName: data.name,
            panelInstanceId: data.instanceId.toString(),
            panelVersion: data.version.toString()
        };

        raisePanelLoadedServerEvent();
    }

    function raisePanelLoadedServerEvent() {
        $.ajax({
            type: 'POST',
            url: '/dashboard/panel/loaded',
            data: JSON.stringify(periscope.panelIdentity),
            contentType: 'application/json; charset=utf-8',
            dataType: 'json'
        }).done(function (data, status, jqXhr) {
            log('panel loaded complete...');
            log(data);
        }).fail(function (jqXhr, status, err) {
            log('failed to raise panel loaded server event :(');
            log(err);
        });
    }

    return periscope;
} ('panelcontainer'));
